#include "mempool.h"

// 创建内存池
MemoryPool* MemPoolCreate() 
{
    MemoryPool *mempool = (MemoryPool*)malloc(sizeof(MemoryPool));
    if (mempool == NULL)
    {
        return NULL;
    }
    mempool->free_list = NULL;
    mempool->tail = NULL;
    return mempool;
}

/*
* @file mempool.h
* @brief 向系统申请新内存页，并封装为MemBlock(内部使用)
* @param need_size 需要的最小总大小（含头部）
* @return 新块指针（失败返回NULL）
* @author zhw
* @date 2025.10.23 22:57
* @version 1.0
*/
static Block* allocate_new_page(size_t need_size)
{
    // 请关注：计算实际申请的页数量（向上取整,C语言宝藏知识）
    size_t pagecount = (need_size + PAGE_SIZE - 1) / PAGE_SIZE;
    size_t total_size = pagecount * PAGE_SIZE;

    Block* block_ptr = (Block*)malloc(total_size);
    if (block_ptr == NULL)
    {
        return NULL;
    }

    block_ptr->total_size = total_size;
    block_ptr->is_free = 1;
    block_ptr->prev = NULL;
    block_ptr->next = NULL;
    return block_ptr;
}

/*
* @file mempool.h
* 从空闲链表中查找适配的块（最佳适配）
* @param pool 内存池句柄
* @param need_size 需要的总大小（含头部）
* @return 适配的块（未找到返回NULL）
* @author zhw
* @date 2025.10.23 23:10
* @version 1.0
*/
static Block* find_fit_block(MemoryPool* pool,size_t need_size)
{
    if (pool == NULL)
    {
        return NULL;
    }
    
    Block* cur = pool->free_list;
    while (cur != NULL)
    {
        if (cur->is_free == 1 && cur->total_size >= need_size)
        {
            return cur;
        }
        cur = cur->next;
    }
    return NULL;
}

/*
* @file mempool.h
* 将空闲块插入链表（按地址排序）
* @param pool 内存池句柄
* @param block 要插入的空闲块
* @return 失败:-1 成功:0
* @author zhw
* @date 2025.10.23 23:40
* @version 1.0
*/
static int insert_free_block(MemoryPool* pool,Block* block) 
{
    if (pool == NULL)
    {
        return -1;
    }

    if (pool->free_list == NULL)// 链表为空
    {
        pool->free_list = block;
        pool->tail = block;
    }
    else if (block < pool->free_list)// 插入头部---// 按内存地址从小到大插入（便于合并相邻块）
    {
        block->next = pool->free_list;
        pool->free_list->prev = block;
        pool->free_list = block;
    }
    else if (block > pool->free_list)// 中间或尾部插入
    {
        Block* blk = pool->free_list;
        // 请关注：while (blk && blk < block) //这样写会导致blk->next为空时报错
        while (blk->next && blk->next < block)
        {
            blk = blk->next;
        }

        //请关注：双向链表的四条线(以新增元素为中心：后出、前出、后进，前进的顺序)
        block->next = blk->next;
        block->prev = blk;
        if (blk->next != NULL)
        {
            blk->next->prev = block;
        }
        else
        {
            pool->tail = block;
        }
        blk->next = block;
    }
    return 0;
}

/*
* @file mempool.h
* 合并相邻的空闲块
* @param pool 内存池句柄
* @param block 要合并的块
* @return 失败:-1 成功:0
* @author zhw
* @date 2025.10.24 00:26
* @version 1.0
*/
static int merge_adjacent_blocks(MemoryPool* pool,Block* block) 
{
    if (pool == NULL)
    {
        return -1;
    }
    if (block->prev != NULL && block->prev->is_free == 1)//向前合并
    {
        Block* prev = block->prev;
        prev->total_size += block->total_size;
        prev->next = block->next;
        if (block->next != NULL)
        {
            block->next->prev = prev;
        }
        else
        {
            pool->tail = prev;
        }
        block = prev;
    }
    
    if (block->next != NULL && block->next->is_free == 1)//向后合并
    {
        Block* nex = block->next;
        block->total_size += nex->total_size;
        block->next = nex->next;
        if (nex->next != NULL)
        {
            nex->next->prev = block;
        }
        else
        {
            pool->tail = block;
        }
    }
    return 0;
}

// 从内存池分配一块内存
void* MemPoolAlloc(MemoryPool* pool, size_t size)
{
    if (!pool || size == 0)
    {
        return NULL;
    }
    
    // 计算实际需要的总大小（含头部）
    size_t need_total_size = size + sizeof(Block);

    // 查找适配的空闲块
    Block *block = find_fit_block(pool,need_total_size);

    // 无适配块，申请新页
    if (!block)
    {
        block = allocate_new_page(need_total_size);
        if (!block)
        {
            return NULL;
        }
        insert_free_block(pool,block);
    }
    
    // 若块过大，切割为两部分
    if (block->total_size - need_total_size >= sizeof(Block) + 10)
    {
        Block* newBlock = (Block*)((char*)block + need_total_size);
        newBlock->total_size = block->total_size - need_total_size;
        newBlock->is_free = 1;

        newBlock->next = block->next;
        newBlock->prev = block;
        if (block->next)
        {
            block->next->prev = newBlock;
        }
        else
        {
            pool->tail = newBlock;
        }
        block->total_size = need_total_size; 
        block->next = newBlock;
    }
    
    // 标记为已分配，并从空闲链表移除
    block->is_free = 0;
    if (block->prev)
    {
        block->prev->next = block->next;
    }
    else
    {
        pool->free_list = block->next;
    }
    
    if (block->next)
    {
        block->next->prev = block->prev;
    }
    else
    {
        pool->tail = block->prev;
    }
    
    block->prev = block->next = NULL;

    // 返回用户可用内存（跳过头部）
    return (char*)block + sizeof(Block);
}

// 将内存块释放回内存池
int MemPoolFree(MemoryPool* pool, void* ptr) 
{
    //判断参数合法性
    if (!pool || !ptr)
    {
        return -1;
    }

    Block* block = (Block*)((char*)ptr - sizeof(Block));
    if (block->is_free != 0)
    {
        return -1;
    }
    
    block->is_free = 1;
    insert_free_block(pool,block);
    merge_adjacent_blocks(pool,block);
    return 0;
}

// 销毁内存池
int MemPoolDestroy(MemoryPool* pool) 
{
    if (!pool)
    {
        return -1;
    }
    
    // 潜在问题与补充说明：
    // 未记录所有内存页：代码中通过遍历 free_list 释放内存页，这依赖于 “所有内存页都至少有一个空闲块在链表中”。
    // 但如果内存池中的所有块都处于 “已分配” 状态（free_list 为空），则会导致内存页无法被释放（内存泄漏）。
    // 优化方案：内存池应单独维护一个 “所有内存页” 的链表，确保销毁时能遍历所有页，而非依赖 free_list。
    Block* block = pool->free_list;
    while (block)
    {
        // 遍历所有空闲块（已分配的块也会随页释放）
        Block* blocknxt = block->next;
        free(block);// 释放整个内存页
        block = block->next;
    }
    
    free(pool);
    return 0;
}